package com.resifind.www.service.impl;

import com.resifind.www.constant.ErrorCode;
import com.resifind.www.constant.Regex;
import com.resifind.www.constant.UserTypes;
import com.resifind.www.dao.ClientDao;
import com.resifind.www.dao.MerchantDao;
import com.resifind.www.dao.UserDao;
import com.resifind.www.dao.impl.ClientDaoImpl;
import com.resifind.www.dao.impl.MerchantDaoImpl;
import com.resifind.www.dao.impl.UserDaoImpl;
import com.resifind.www.exception.BaseException;
import com.resifind.www.exception.Resp;
import com.resifind.www.exception.UserException;
import com.resifind.www.po.*;
import com.resifind.www.service.UserService;
import com.resifind.www.util.EncodeUtil;
import com.resifind.www.util.JdbcUtils;

import java.sql.Connection;
import java.util.Base64;

/**
 * @author 36069
 */
public class UserServiceImpl implements UserService {
    private final UserDao userDao = new UserDaoImpl();
    private final ClientDao clientDao = new ClientDaoImpl();
    private final MerchantDao merchantDao = new MerchantDaoImpl();

    @Override
    public Resp<String> register(String phoneNum, String password, String userType) {
        //判断手机号，密码和用户类型是否符合格式
        if (!phoneNum.matches(Regex.PHONE_NUM) || !password.matches(Regex.PASSWORD) || userType == null || userType.isEmpty()) {
            throw UserException.phoneNumberAlreadyRegistered();
        }
        //判断手机号是否存在
        if (userDao.queryUser(phoneNum) != null) {
            throw UserException.phoneNumberAlreadyRegistered();
        }
        //添加用户并按照用户类型添加客户或商户
        Connection conn = null;
        try {
            conn = JdbcUtils.getConn();
            JdbcUtils.beginTransaction(conn);
            //对密码进行加密
            byte[] salt = EncodeUtil.generateSalt();
            String hashPassword = EncodeUtil.encode(password, salt);
            String saltStr = Base64.getEncoder().encodeToString(salt);
            //添加用户
            User user = new User(null, phoneNum, hashPassword, saltStr);
            int userId = userDao.addUser(user, conn);
            boolean result;
            //添加用户失败，回滚事务
            if (userId == -1) {
                JdbcUtils.rollbackTransaction(conn);
                throw new BaseException(ErrorCode.DB_ERROR);
            }
            //添加用户成功，添加客户或商户
            if (userType.equals(UserTypes.CLIENT)) {
                //添加客户
                result = clientDao.addClient(userId, conn);
            } else if (userType.equals(UserTypes.MERCHANT)) {
                //添加商户
                result = merchantDao.addMerchant(userId, conn);
            } else {
                //添加用户类型失败，回滚事务
                JdbcUtils.rollbackTransaction(conn);
                throw UserException.userTypeError();
            }
            //提交事务或回滚事务
            if (result) {
                JdbcUtils.commitTransaction(conn);
                return Resp.success("success");
            } else {
                JdbcUtils.rollbackTransaction(conn);
                throw new BaseException(ErrorCode.DB_ERROR);
            }
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            JdbcUtils.rollbackTransaction(conn);
            throw new BaseException(ErrorCode.SERVER_ERROR);
        } finally {
            JdbcUtils.closeConn(conn, null, null);
        }
    }

    @Override
    public Resp<User> login(String phoneNum, String password) {
        //查询用户
        User user = userDao.queryUser(phoneNum);
        if (user == null) {
            throw UserException.phoneNumberOrPasswordError();
        }
        //获取盐和hash密码进行校验
        boolean verify = EncodeUtil.verify(password, user.getSalt(), user.getHasePassword());
        if (!verify) {
            throw UserException.phoneNumberOrPasswordError();
        }
        //根据用户id获取用户类型
        String userType = userDao.queryUserTypeById(user.getId());
        if (userType == null) {
            throw UserException.getUserTypeError();
        }
        user.setUserType(userType);
        user.setSalt(null);
        user.setHasePassword(null);
        return Resp.success(user);
    }

    @Override
    public Resp<String> forgetPassword(String phoneNum, String newPassword) {
        //判断手机号和密码是否符合格式
        if (!phoneNum.matches(Regex.PHONE_NUM) || !newPassword.matches(Regex.PASSWORD)) {
            throw UserException.phoneNumPasswordFormatError();
        }
        //判断手机号是否存在，并获取更新用户对象获取id
        User user = userDao.queryUser(phoneNum);
        if (user == null) {
            throw UserException.phoneNumNotExist();
        }
        Connection conn = null;
        try {
            conn = JdbcUtils.getConn();
            JdbcUtils.beginTransaction(conn);
            //对新密码进行加密
            byte[] salt = EncodeUtil.generateSalt();
            String hashPassword = EncodeUtil.encode(newPassword, salt);
            String saltStr = Base64.getEncoder().encodeToString(salt);
            //修改密码
            if (userDao.updatePassword(user.getId(), hashPassword, saltStr, conn)) {
                JdbcUtils.commitTransaction(conn);
                return Resp.success("success");
            }
            //修改密码失败，回滚事务
            JdbcUtils.rollbackTransaction(conn);
            throw new BaseException(ErrorCode.DB_ERROR);
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            JdbcUtils.rollbackTransaction(conn);
            throw new BaseException(ErrorCode.SERVER_ERROR);
        } finally {
            JdbcUtils.closeConn(conn, null, null);
        }
    }

    @Override
    public Resp<UserFullInfo<Object>> checkLogin(User user) {
        if (user.getUserType().equals(UserTypes.CLIENT)) {
            Client client = clientDao.queryClientByUserId(user.getId());
            return Resp.success(new UserFullInfo<>(user, client));
        } else if (user.getUserType().equals(UserTypes.MERCHANT)) {
            Merchant merchant = merchantDao.queryMerchantByUserId(user.getId());
            return Resp.success(new UserFullInfo<>(user, merchant));
        } else {
            throw UserException.userTypeError();
        }
    }

}
